#define LOG_TAG "ISharedBuffer"

#include <utils/Log.h>
#include <binder/MemoryBase.h>

#include "ISharedBuffer.h"

using namespace android;

enum {
    CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
    COMMIT_BUFFER = IBinder::FIRST_CALL_TRANSACTION + 1,
    RELEASE_BUFFER = IBinder::FIRST_CALL_TRANSACTION + 2,
};

class BpSharedBuffer : public BpInterface<ISharedBuffer> {
public:
    BpSharedBuffer(const sp<IBinder> &impl)
            : BpInterface<ISharedBuffer>(impl) {
    }

public:
    sp<SyncBuffer> createBuffer(size_t size, const char *name) {
        Parcel data;
        data.writeInterfaceToken(ISharedBuffer::getInterfaceDescriptor());
        data.writeInt32(size);
        data.writeCString(name ? name : "Shared-Buffer");

        Parcel reply;
        remote()->transact(CREATE_BUFFER, data, &reply);

        sp<IMemory> mem = interface_cast<IMemory>(reply.readStrongBinder());
        sp<SyncBuffer> buffer = new SyncBuffer(mem);
        return buffer;
    }

    status_t commitBuffer(bool async = false) {
        Parcel data;
        data.writeInterfaceToken(ISharedBuffer::getInterfaceDescriptor());
        Parcel reply;
        remote()->transact(COMMIT_BUFFER, data, &reply, async ? IBinder::FLAG_ONEWAY : 0);
        return async ? OK : reply.readInt32();
    }

    status_t releaseBuffer() {
        Parcel data;
        data.writeInterfaceToken(ISharedBuffer::getInterfaceDescriptor());
        Parcel reply;
        remote()->transact(RELEASE_BUFFER, data, &reply);
        return reply.readInt32();
    }
};

IMPLEMENT_META_INTERFACE(SharedBuffer, "com.android.ISharedBuffer");

status_t
BnSharedBuffer::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
    switch (code) {
        case CREATE_BUFFER: {
            CHECK_INTERFACE(ISharedBuffer, data, reply);

            size_t size = data.readInt32();
            const char *name = data.readCString();

            sp<SyncBuffer> buffer = createBuffer(size, name);
            if (buffer != NULL) {
                reply->writeStrongBinder(IInterface::asBinder(buffer->getMemory()));
            }

            return NO_ERROR;
        }
        case COMMIT_BUFFER: {
            CHECK_INTERFACE(ISharedBuffer, data, reply);
            status_t ret = commitBuffer();
            reply->writeInt32(ret);
            return NO_ERROR;
        }
        case RELEASE_BUFFER: {
            CHECK_INTERFACE(ISharedBuffer, data, reply);
            status_t ret = releaseBuffer();
            reply->writeInt32(ret);
            return NO_ERROR;
        }
        default: {
            return BBinder::onTransact(code, data, reply, flags);
        }
    }
}
